dojo.provide("miaigo.model.Collection");

dojo.require("miaigo.model.Game");
dojo.require("miaigo.model.GameReader");

dojo.require("miaigo.model.sgf.SGFGameReader");

dojo.declare(
    "miaigo.model.Collection",
    null,
    {
	_games: null,

	// game source
	gameString: null,
	gameFormat: null,
	gameURL: null,

	// callbacks
	onProgress: null,
	onLoad: null,
	onError: null,
	onWarning: null,

	constructor: function()
	{
	    this._games = [];
	},

	addGame: function(/* miaigo.model.Game */game)
	{
	    this._games.push(game);
	},

	removeGame: function(/* miaigo.model.Game */game)
	{
	    var i = this.indexOf(game);
	    if (i >= 0)
	    {
		this._games.splice(i, 1);
	    }
	},

	indexOf: function(/* miaigo.model.Game */game)
	{
	    for (var i=0; i<this._games.length; i++)
	    {
		if (this._games[i] == game)
		{
		    return i;
		}
	    }

	    return -1;
	},

	getGameCount: function()
	{
	    return this._games.length;
	},

	getGame: function(gameIndex)
	{
	    return this._games[gameIndex];
	},

	createNewGame: function()
	{
	    console.error("miaigo.model.Collection.createNewName NYI");
	},

	// loadParam:
	// - gameString: A string as game content
	// - gameType: A string as game format (e.g. "sgf")
	// - gameURL: An URL to load the game. If this is specified, gameString
	//            and gameType will be ignored.
	// - onProgress: function(Number)
	//     Optional. If specified, call and pass it a float value for
	//     percentage of loading progress.
	// - onLoad: function([miaigo.model.Game])
	//     Optional. If specified, call it when game loaded. When called,
	//     the parameter is an array of games loaded.
	// - onError: function(String)
	//     Optional. If specified, call it when failed to load a game. The
	//     string parameter passed indicte the error details.
	// - onWarning: function(String)
	//     Optional. If specified, call it when there is any warning to
	//     present.
	load: function(/* Object */loadParam)
	{
	    if (loadParam)
	    {
		// set callbacks
		this.onProgress = loadParam.onProgress;
		this.onLoad = loadParam.onLoad;
		this.onError = loadParam.onError;
		this.onWarning = loadParam.onWarning;

		// load game
		if (loadParam.gameURL)
		{
		    this.gameURL = loadParam.gameURL;
		    this._loadURL();
		}
		else
		{
		    this.gameString = loadParam.gameString;
		    this.gameFormat = loadParam.gameFormat;
		    this._loadString();
		}
	    }
	},

	_loadString: function()
	{
	    var readerParam =
		{
		    onProgress: dojo.hitch(this, "_onGameReaderProgress"),
		    onLoad: dojo.hitch(this, "_onGameReaderLoad"),
		    onError: dojo.hitch(this, "_onGameReaderError"),
		    onWarning: dojo.hitch(this, "_onGameReaderWarning")
		};
	    var reader = this._createGameReader(readerParam);
	    if (reader)
	    {
		reader.asyncReadGame(this.gameString);
	    }
	},

	_loadURL: function()
	{
	    var ioArgs =
		{
		    url: this.gameURL,
		    error: dojo.hitch(this, "_onURLLoadError"),
		    load: dojo.hitch(this, "_onURLLoadSuccess")
		};

	    dojo.xhrGet(ioArgs);
	},

	_onURLLoadError: function(resp, ioArgs)
	{
	    this.onError(resp);
	},

	_onURLLoadSuccess: function(resp, ioArgs)
	{
	    this.gameString = resp;
	    // TODO: set game type by response
	    this.gameType = "sgf";

	    this._loadString(resp);
	},

	// create a miaigo.model.GameReader
	_createGameReader: function(readerParam)
	{
	    // TODO: create reader according to this.gameType
	    var reader = new miaigo.model.sgf.SGFGameReader(readerParam);

	    return reader;
	},

	// callbacks to game reader
	_onGameReaderProgress: function(/* String */progressString)
	{
	    // TODO: calculate overall progress percentage
	    if (this.onProgress)
	    {
		this.onProgress(progressString);
	    }
	},

	_onGameReaderError: function(/* String */errorString)
	{
	    if (this.onError)
	    {
		this.onError(errorString);
	    }
	},

	_onGameReaderLoad: function(/* [miaigo.model.Game] */games)
	{
	    this._games = games;

	    // build moves
	    if (this._games && this._games.length > 0)
	    {
		for (var i=0; i<this._games.length; i++)
		{
		    this._games[i].buildMoveTree();
		}
	    }

	    // loading finished, call back to notified caller
	    if (this.onLoad)
	    {
		this.onLoad(this._games);
	    }
	},

	_onGameReaderWarning: function(/* String */warningString)
	{
	    if (this.onWarning)
	    {
		this.onWarning(warningString);
	    }
	}
    });